package analiseSintatica.Regras.Blocos;

import AnaliseLexicaFinal.EstruturaDeDados.LinkToken;
import analiseSemantica.ErroSemantico;
import analiseSemantica.Tipos.TipoSemantico;
import analiseSemantica.Tipos.TiposSemanticos;
import analiseSemantica.estruturadedados.Escopo;
import analiseSintatica.AnalisadorSintatico;
import analiseSintatica.ErroSintaticoException;
import analiseSintatica.Regras.Regra;

import java.util.LinkedList;

/**
 *
 * @author anderson
 * @date  6:42:13 PM
 */
public class RegraPrograma extends Regra {

    protected static Regra instancia;

    protected String estrutura = "<diretivas> <decls_inicial> void main '(' ')' <corpo_funcao>";
    
    /**
     * Construtor do singleton
     */
    private RegraPrograma() {
    }

    /**
     * Retorna a unica instancia dessa classe.
     * @return
     */
    public static RegraPrograma getInstance() {
        if (instancia == null) {
            instancia = new RegraPrograma();
        }
        return (RegraPrograma) instancia;

    }

	@Override
    public TiposSemanticos analisar(LinkedList<LinkToken> listaTokens) throws ErroSintaticoException {
    	
    	AnalisadorSintatico.escopoatual = new Escopo(null); //Criacao do escopo global nesse caso
    	RegraDiretivas.getInstance().analisar(listaTokens);
    	RegraDeclsInicial.getInstance().analisar(listaTokens);
    	reconheceToken(listaTokens, "void", estrutura);
        reconheceToken(listaTokens, "main", estrutura);
        reconheceLexema(listaTokens, "delimitador", "(", estrutura);
        reconheceLexema(listaTokens, "delimitador", ")", estrutura);

        AnalisadorSintatico.escopoatual = new Escopo(AnalisadorSintatico.escopoatual);
        TiposSemanticos tipomain = RegraCorpoFuncao.getInstance().analisar(listaTokens); //Pegando retorno do CorpoFuncao
        while (tipomain != null && tipomain.size() != 0){ //Retornar o erro quando main nao retornar void
        	TipoSemantico tipo = tipomain.removeTipos();
        	AnalisadorSintatico.errosemanticos.add(new ErroSemantico("Corpo do main deve retornar void", tipo.getLinha()));
        }
        return null;
    }

    @Override
    protected void setPrimeiro() {
    	this.primeiro = RegraDiretivas.getInstance().getPrimeiro();
    	primeiro.remove("e");
    	primeiro = getUniao(primeiro, RegraDeclsInicial.getInstance().getPrimeiro());
    	primeiro.remove("e");
    	primeiro = getUniao(primeiro, "void");
    }
    
}